package protocol

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"sync"
	"tcp_server/common"
	"time"
)

var UnAuthConnection sync.Map // 没有认证的连接对象集合
var ClientConnection sync.Map // 认证过的连接对象集合

/*------------------------- 客户连接对象 ---------------------------*/
type ClientConn struct {
	ConnId        string        // 唯一id
	UserId        string        // 客户id（用于业务）
	Authenticated bool          // 是否认证过
	SessionKey    string        // AES会话密钥
	Conn          net.Conn      // 连接对象
	createTime    int64         // 连接的时间戳
	reader        *bufio.Reader // 基于Conn的读缓存区
	Addr          string        // 套接字信息
	closed        bool          // 是否关闭状态

	ReadChan  chan []byte // 读通道，认证后使用
	WriteChan chan []byte // 写通道，认证后使用
	StopChan  chan bool   // 是否关闭读通道协程

	DwPubTimes int // 公钥发送次数
	UpSeeTimes int // 收到会话密钥次数
	UpPwdTimes int // 收到用户口令验证次数
}

// 关闭连接
func (c *ClientConn) Close() {
	if c.Conn != nil && !c.closed {
		_ = c.Conn.Close()
		c.closed = true
		if c.Authenticated {
			close(c.ReadChan)
			close(c.WriteChan)
			close(c.StopChan)
		}
		c.LogConn("close connection")
	}
	if c.UserId != "" {
		ClientConnection.Delete(c.UserId)
	}
	UnAuthConnection.Delete(c.ConnId)
}

// 读取数据
func (c *ClientConn) Read() ([]byte, error) {
	return Decode(c.reader)
}

// 发送数据
func (c *ClientConn) Write(data []byte) (int, error) {
	sendByte, err := Encode(data)
	if err != nil {
		return 0, nil
	}
	n, err := c.Conn.Write(sendByte)
	if err != nil {
		return n, err
	}
	return n, nil
}

// 读取数据并且进行解密，用户认证之后的通信
func (c *ClientConn) ReadDecrypt() ([]byte, error) {

	data, err := c.Read()
	if err != nil {
		return []byte{}, err
	}
	decData, err := common.AesDecrypt(data, []byte(c.SessionKey))
	if err != nil {
		return []byte{}, nil
	}
	c.LogRead(string(decData))
	return decData, nil
}

// 发送数据并且进行加密，用户认证之后的通信
func (c *ClientConn) WriteDecrypt(sendData []byte) error {

	c.LogWrite(string(sendData))
	data, err := common.AesEncrypt(sendData, []byte(c.SessionKey))
	if err != nil {
		data = []byte{}
	}

	_, err = c.Write(data)
	if err != nil {
		return err
	}
	return nil
}

// 判断连接是否超时
func (c *ClientConn) Expire(nowTime int64, timeout int64) bool {
	return nowTime-c.createTime > timeout
}

// 返回连接对象的基本信息
func (c *ClientConn) Info() string {
	info := fmt.Sprintf("Conn[%s, %s, %s, %s]", c.ConnId, c.UserId, c.Addr, c.SessionKey)
	return info
}

// 用于日志的信息
func (c *ClientConn) LogInfo() string {
	info := fmt.Sprintf("Conn[%s, %s]", c.UserId, c.Addr)
	return info
}

// 日志打印
func (c *ClientConn) LogError(info ...interface{}) {
	log.Println(c.LogInfo(), "[error]", info)
}

func (c *ClientConn) LogConn(info ...interface{}) {
	log.Println(c.LogInfo(), "[conn]", info)
}

func (c *ClientConn) LogRead(info ...interface{}) {
	log.Println(c.LogInfo(), "[read]", info)
}

func (c *ClientConn) LogWrite(info ...interface{}) {
	log.Println(c.LogInfo(), "[write]", info)
}

// 封装连接信息
func CreateClientConn(conn net.Conn) *ClientConn {
	client := &ClientConn{
		ConnId:        common.GetUUID(),
		Conn:          conn,
		createTime:    time.Now().Unix(),
		reader:        bufio.NewReader(conn),
		Authenticated: false,
		Addr:          conn.RemoteAddr().String(),
		closed:        false,
	}
	UnAuthConnection.Store(client.ConnId, client)
	client.LogConn("conn connected")
	return client
}
